home *** CD-ROM | disk | FTP | other *** search
/ Aminet 34 / Aminet 34 (2000)(Schatztruhe)[!][Dec 1999].iso / Aminet / util / gnu / unixcmds.lha / unixcmds / src / grep-2.1 / kwset.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-06  |  20.8 KB  |  803 lines

  1. /* kwset.c - search for any of a set of keywords.
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17.    02111-1307, USA.  */
  18.  
  19. /* Written August 1989 by Mike Haertel.
  20.    The author may be reached (Email) at the address mike@ai.mit.edu,
  21.    or (US mail) as Mike Haertel c/o Free Software Foundation. */
  22.  
  23. /* The algorithm implemented by these routines bears a startling resemblence
  24.    to one discovered by Beate Commentz-Walter, although it is not identical.
  25.    See "A String Matching Algorithm Fast on the Average," Technical Report,
  26.    IBM-Germany, Scientific Center Heidelberg, Tiergartenstrasse 15, D-6900
  27.    Heidelberg, Germany.  See also Aho, A.V., and M. Corasick, "Efficient
  28.    String Matching:  An Aid to Bibliographic Search," CACM June 1975,
  29.    Vol. 18, No. 6, which describes the failure function used below. */
  30.  
  31. #ifdef HAVE_CONFIG_H
  32. # include <config.h>
  33. #endif
  34. #include <sys/types.h>
  35. #include "system.h"
  36. #include "kwset.h"
  37. #include "obstack.h"
  38.  
  39. #ifdef GREP
  40. extern char *xmalloc();
  41. # undef malloc
  42. # define malloc xmalloc
  43. #endif
  44.  
  45. #define NCHAR (UCHAR_MAX + 1)
  46. #define obstack_chunk_alloc malloc
  47. #define obstack_chunk_free free
  48.  
  49. /* Balanced tree of edges and labels leaving a given trie node. */
  50. struct tree
  51. {
  52.   struct tree *llink;        /* Left link; MUST be first field. */
  53.   struct tree *rlink;        /* Right link (to larger labels). */
  54.   struct trie *trie;        /* Trie node pointed to by this edge. */
  55.   unsigned char label;        /* Label on this edge. */
  56.   char balance;            /* Difference in depths of subtrees. */
  57. };
  58.  
  59. /* Node of a trie representing a set of reversed keywords. */
  60. struct trie
  61. {
  62.   unsigned int accepting;    /* Word index of accepted word, or zero. */
  63.   struct tree *links;        /* Tree of edges leaving this node. */
  64.   struct trie *parent;        /* Parent of this node. */
  65.   struct trie *next;        /* List of all trie nodes in level order. */
  66.   struct trie *fail;        /* Aho-Corasick failure function. */
  67.   int depth;            /* Depth of this node from the root. */
  68.   int shift;            /* Shift function for search failures. */
  69.   int maxshift;            /* Max shift of self and descendents. */
  70. };
  71.  
  72. /* Structure returned opaquely to the caller, containing everything. */
  73. struct kwset
  74. {
  75.   struct obstack obstack;    /* Obstack for node allocation. */
  76.   int words;            /* Number of words in the trie. */
  77.   struct trie *trie;        /* The trie itself. */
  78.   int mind;            /* Minimum depth of an accepting node. */
  79.   int maxd;            /* Maximum depth of any node. */
  80.   unsigned char delta[NCHAR];    /* Delta table for rapid search. */
  81.   struct trie *next[NCHAR];    /* Table of children of the root. */
  82.   char *target;            /* Target string if there's only one. */
  83.   int mind2;            /* Used in Boyer-Moore search for one string. */
  84.   char *trans;            /* Character translation table. */
  85. };
  86.  
  87. /* prototypes */
  88. static void enqueue PARAMS((struct tree *, struct trie **));
  89. static void treefails PARAMS((register struct tree *, struct trie *, struct trie *));
  90. static void treedelta PARAMS((register struct tree *,register unsigned int, unsigned char *));
  91. static int  hasevery PARAMS((register struct tree *, register struct tree *));
  92. static void treenext PARAMS((struct tree *, struct trie **));
  93. static char * bmexec PARAMS((kwset_t, char *, size_t));
  94. static char * cwexec PARAMS((kwset_t, char *, size_t, struct kwsmatch *));
  95.  
  96. /* Allocate and initialize a keyword set object, returning an opaque
  97.    pointer to it.  Return NULL if memory is not available. */
  98. kwset_t
  99. kwsalloc(trans)
  100.      char *trans;
  101. {
  102.   struct kwset *kwset;
  103.  
  104.   kwset = (struct kwset *) malloc(sizeof (struct kwset));
  105.   if (!kwset)
  106.     return 0;
  107.  
  108.   obstack_init(&kwset->obstack);
  109.   kwset->words = 0;
  110.   kwset->trie
  111.     = (struct trie *) obstack_alloc(&kwset->obstack, sizeof (struct trie));
  112.   if (!kwset->trie)
  113.     {
  114.       kwsfree((kwset_t) kwset);
  115.       return 0;
  116.     }
  117.   kwset->trie->accepting = 0;
  118.   kwset->trie->links = 0;
  119.   kwset->trie->parent = 0;
  120.   kwset->trie->next = 0;
  121.   kwset->trie->fail = 0;
  122.   kwset->trie->depth = 0;
  123.   kwset->trie->shift = 0;
  124.   kwset->mind = INT_MAX;
  125.   kwset->maxd = -1;
  126.   kwset->target = 0;
  127.   kwset->trans = trans;
  128.  
  129.   return (kwset_t) kwset;
  130. }
  131.  
  132. /* Add the given string to the contents of the keyword set.  Return NULL
  133.    for success, an error message otherwise. */
  134. char *
  135. kwsincr(kws, text, len)
  136.      kwset_t kws;
  137.      char *text;
  138.      size_t len;
  139. {
  140.   struct kwset *kwset;
  141.   register struct trie *trie;
  142.   register unsigned char label;
  143.   register struct tree *link;
  144.   register int depth;
  145.   struct tree *links[12];
  146.   enum { L, R } dirs[12];
  147.   struct tree *t, *r, *l, *rl, *lr;
  148.  
  149.   kwset = (struct kwset *) kws;
  150.   trie = kwset->trie;
  151.   text += len;
  152.  
  153.   /* Descend the trie (built of reversed keywords) character-by-character,
  154.      installing new nodes when necessary. */
  155.   while (len--)
  156.     {
  157.       label = kwset->trans ? kwset->trans[(unsigned char) *--text] : *--text;
  158.  
  159.       /* Descend the tree of outgoing links for this trie node,
  160.      looking for the current character and keeping track
  161.      of the path followed. */
  162.       link = trie->links;
  163.       links[0] = (struct tree *) &trie->links;
  164.       dirs[0] = L;
  165.       depth = 1;
  166.  
  167.       while (link && label != link->label)
  168.     {
  169.       links[depth] = link;
  170.       if (label < link->label)
  171.         dirs[depth++] = L, link = link->llink;
  172.       else
  173.         dirs[depth++] = R, link = link->rlink;
  174.     }
  175.  
  176.       /* The current character doesn't have an outgoing link at
  177.      this trie node, so build a new trie node and install
  178.      a link in the current trie node's tree. */
  179.       if (!link)
  180.     {
  181.       link = (struct tree *) obstack_alloc(&kwset->obstack,
  182.                            sizeof (struct tree));
  183.       if (!link)
  184.         return _("memory exhausted");
  185.       link->llink = 0;
  186.       link->rlink = 0;
  187.       link->trie = (struct trie *) obstack_alloc(&kwset->obstack,
  188.                              sizeof (struct trie));
  189.       if (!link->trie)
  190.         return _("memory exhausted");
  191.       link->trie->accepting = 0;
  192.       link->trie->links = 0;
  193.       link->trie->parent = trie;
  194.       link->trie->next = 0;
  195.       link->trie->fail = 0;
  196.       link->trie->depth = trie->depth + 1;
  197.       link->trie->shift = 0;
  198.       link->label = label;
  199.       link->balance = 0;
  200.  
  201.       /* Install the new tree node in its parent. */
  202.       if (dirs[--depth] == L)
  203.         links[depth]->llink = link;
  204.       else
  205.         links[depth]->rlink = link;
  206.  
  207.       /* Back up the tree fixing the balance flags. */
  208.       while (depth && !links[depth]->balance)
  209.         {
  210.           if (dirs[depth] == L)
  211.         --links[depth]->balance;
  212.           else
  213.         ++links[depth]->balance;
  214.           --depth;
  215.         }
  216.  
  217.       /* Rebalance the tree by pointer rotations if necessary. */
  218.       if (depth && ((dirs[depth] == L && --links[depth]->balance)
  219.             || (dirs[depth] == R && ++links[depth]->balance)))
  220.         {
  221.           switch (links[depth]->balance)
  222.         {
  223.         case (char) -2:
  224.           switch (dirs[depth + 1])
  225.             {
  226.             case L:
  227.               r = links[depth], t = r->llink, rl = t->rlink;
  228.               t->rlink = r, r->llink = rl;
  229.               t->balance = r->balance = 0;
  230.               break;
  231.             case R:
  232.               r = links[depth], l = r->llink, t = l->rlink;
  233.               rl = t->rlink, lr = t->llink;
  234.               t->llink = l, l->rlink = lr, t->rlink = r, r->llink = rl;
  235.               l->balance = t->balance != 1 ? 0 : -1;
  236.               r->balance = t->balance != (char) -1 ? 0 : 1;
  237.               t->balance = 0;
  238.               break;
  239.             default:
  240.               abort ();
  241.             }
  242.           break;
  243.         case 2:
  244.           switch (dirs[depth + 1])
  245.             {
  246.             case R:
  247.               l = links[depth], t = l->rlink, lr = t->llink;
  248.               t->llink = l, l->rlink = lr;
  249.               t->balance = l->balance = 0;
  250.               break;
  251.             case L:
  252.               l = links[depth], r = l->rlink, t = r->llink;
  253.               lr = t->llink, rl = t->rlink;
  254.               t->llink = l, l->rlink = lr, t->rlink = r, r->llink = rl;
  255.               l->balance = t->balance != 1 ? 0 : -1;
  256.               r->balance = t->balance != (char) -1 ? 0 : 1;
  257.               t->balance = 0;
  258.               break;
  259.             default:
  260.               abort ();
  261.             }
  262.           break;
  263.         default:
  264.           abort ();
  265.         }
  266.  
  267.           if (dirs[depth - 1] == L)
  268.         links[depth - 1]->llink = t;
  269.           else
  270.         links[depth - 1]->rlink = t;
  271.         }
  272.     }
  273.  
  274.       trie = link->trie;
  275.     }
  276.  
  277.   /* Mark the node we finally reached as accepting, encoding the
  278.      index number of this word in the keyword set so far. */
  279.   if (!trie->accepting)
  280.     trie->accepting = 1 + 2 * kwset->words;
  281.   ++kwset->words;
  282.  
  283.   /* Keep track of the longest and shortest string of the keyword set. */
  284.   if (trie->depth < kwset->mind)
  285.     kwset->mind = trie->depth;
  286.   if (trie->depth > kwset->maxd)
  287.     kwset->maxd = trie->depth;
  288.  
  289.   return 0;
  290. }
  291.  
  292. /* Enqueue the trie nodes referenced from the given tree in the
  293.    given queue. */
  294. static void
  295. enqueue(tree, last)
  296.      struct tree *tree;
  297.      struct trie **last;
  298. {
  299.   if (!tree)
  300.     return;
  301.   enqueue(tree->llink, last);
  302.   enqueue(tree->rlink, last);
  303.   (*last) = (*last)->next = tree->trie;
  304. }
  305.  
  306. /* Compute the Aho-Corasick failure function for the trie nodes referenced
  307.    from the given tree, given the failure function for their parent as
  308.    well as a last resort failure node. */
  309. static void
  310. treefails(tree, fail, recourse)
  311.      register struct tree *tree;
  312.      struct trie *fail;
  313.      struct trie *recourse;
  314. {
  315.   register struct tree *link;
  316.  
  317.   if (!tree)
  318.     return;
  319.  
  320.   treefails(tree->llink, fail, recourse);
  321.   treefails(tree->rlink, fail, recourse);
  322.  
  323.   /* Find, in the chain of fails going back to the root, the first
  324.      node that has a descendent on the current label. */
  325.   while (fail)
  326.     {
  327.       link = fail->links;
  328.       while (link && tree->label != link->label)
  329.     if (tree->label < link->label)
  330.       link = link->llink;
  331.     else
  332.       link = link->rlink;
  333.       if (link)
  334.     {
  335.       tree->trie->fail = link->trie;
  336.       return;
  337.     }
  338.       fail = fail->fail;
  339.     }
  340.  
  341.   tree->trie->fail = recourse;
  342. }
  343.  
  344. /* Set delta entries for the links of the given tree such that
  345.    the preexisting delta value is larger than the current depth. */
  346. static void
  347. treedelta(tree, depth, delta)
  348.      register struct tree *tree;
  349.      register unsigned int depth;
  350.      unsigned char delta[];
  351. {
  352.   if (!tree)
  353.     return;
  354.   treedelta(tree->llink, depth, delta);
  355.   treedelta(tree->rlink, depth, delta);
  356.   if (depth < delta[tree->label])
  357.     delta[tree->label] = depth;
  358. }
  359.  
  360. /* Return true if A has every label in B. */
  361. static int
  362. hasevery(a, b)
  363.      register struct tree *a;
  364.      register struct tree *b;
  365. {
  366.   if (!b)
  367.     return 1;
  368.   if (!hasevery(a, b->llink))
  369.     return 0;
  370.   if (!hasevery(a, b->rlink))
  371.     return 0;
  372.   while (a && b->label != a->label)
  373.     if (b->label < a->label)
  374.       a = a->llink;
  375.     else
  376.       a = a->rlink;
  377.   return !!a;
  378. }
  379.  
  380. /* Compute a vector, indexed by character code, of the trie nodes
  381.    referenced from the given tree. */
  382. static void
  383. treenext(tree, next)
  384.      struct tree *tree;
  385.      struct trie *next[];
  386. {
  387.   if (!tree)
  388.     return;
  389.   treenext(tree->llink, next);
  390.   treenext(tree->rlink, next);
  391.   next[tree->label] = tree->trie;
  392. }
  393.  
  394. /* Compute the shift for each trie node, as well as the delta
  395.    table and next cache for the given keyword set. */
  396. char *
  397. kwsprep(kws)
  398.      kwset_t kws;
  399. {
  400.   register struct kwset *kwset;
  401.   register int i;
  402.   register struct trie *curr, *fail;
  403.   register char *trans;
  404.   unsigned char delta[NCHAR];
  405.   struct trie *last, *next[NCHAR];
  406.  
  407.   kwset = (struct kwset *) kws;
  408.  
  409.   /* Initial values for the delta table; will be changed later.  The
  410.      delta entry for a given character is the smallest depth of any
  411.      node at which an outgoing edge is labeled by that character. */
  412.   if (kwset->mind < 256)
  413.     for (i = 0; i < NCHAR; ++i)
  414.       delta[i] = kwset->mind;
  415.   else
  416.     for (i = 0; i < NCHAR; ++i)
  417.       delta[i] = 255;
  418.  
  419.   /* Check if we can use the simple boyer-moore algorithm, instead
  420.      of the hairy commentz-walter algorithm. */
  421.   if (kwset->words == 1 && kwset->trans == 0)
  422.     {
  423.       /* Looking for just one string.  Extract it from the trie. */
  424.       kwset->target = obstack_alloc(&kwset->obstack, kwset->mind);
  425.       for (i = kwset->mind - 1, curr = kwset->trie; i >= 0; --i)
  426.     {
  427.       kwset->target[i] = curr->links->label;
  428.       curr = curr->links->trie;
  429.     }
  430.       /* Build the Boyer Moore delta.  Boy that's easy compared to CW. */
  431.       for (i = 0; i < kwset->mind; ++i)
  432.     delta[(unsigned char) kwset->target[i]] = kwset->mind - (i + 1);
  433.       kwset->mind2 = kwset->mind;
  434.       /* Find the minimal delta2 shift that we might make after
  435.      a backwards match has failed. */
  436.       for (i = 0; i < kwset->mind - 1; ++i)
  437.     if (kwset->target[i] == kwset->target[kwset->mind - 1])
  438.       kwset->mind2 = kwset->mind - (i + 1);
  439.     }
  440.   else
  441.     {
  442.       /* Traverse the nodes of the trie in level order, simultaneously
  443.      computing the delta table, failure function, and shift function. */
  444.       for (curr = last = kwset->trie; curr; curr = curr->next)
  445.     {
  446.       /* Enqueue the immediate descendents in the level order queue. */
  447.       enqueue(curr->links, &last);
  448.  
  449.       curr->shift = kwset->mind;
  450.       curr->maxshift = kwset->mind;
  451.  
  452.       /* Update the delta table for the descendents of this node. */
  453.       treedelta(curr->links, curr->depth, delta);
  454.  
  455.       /* Compute the failure function for the decendents of this node. */
  456.       treefails(curr->links, curr->fail, kwset->trie);
  457.  
  458.       /* Update the shifts at each node in the current node's chain
  459.          of fails back to the root. */
  460.       for (fail = curr->fail; fail; fail = fail->fail)
  461.         {
  462.           /* If the current node has some outgoing edge that the fail
  463.          doesn't, then the shift at the fail should be no larger
  464.          than the difference of their depths. */
  465.           if (!hasevery(fail->links, curr->links))
  466.         if (curr->depth - fail->depth < fail->shift)
  467.           fail->shift = curr->depth - fail->depth;
  468.  
  469.           /* If the current node is accepting then the shift at the
  470.          fail and its descendents should be no larger than the
  471.          difference of their depths. */
  472.           if (curr->accepting && fail->maxshift > curr->depth - fail->depth)
  473.         fail->maxshift = curr->depth - fail->depth;
  474.         }
  475.     }
  476.  
  477.       /* Traverse the trie in level order again, fixing up all nodes whose
  478.      shift exceeds their inherited maxshift. */
  479.       for (curr = kwset->trie->next; curr; curr = curr->next)
  480.     {
  481.       if (curr->maxshift > curr->parent->maxshift)
  482.         curr->maxshift = curr->parent->maxshift;
  483.       if (curr->shift > curr->maxshift)
  484.         curr->shift = curr->maxshift;
  485.     }
  486.  
  487.       /* Create a vector, indexed by character code, of the outgoing links
  488.      from the root node. */
  489.       for (i = 0; i < NCHAR; ++i)
  490.     next[i] = 0;
  491.       treenext(kwset->trie->links, next);
  492.  
  493.       if ((trans = kwset->trans) != 0)
  494.     for (i = 0; i < NCHAR; ++i)
  495.       kwset->next[i] = next[(unsigned char) trans[i]];
  496.       else
  497.     for (i = 0; i < NCHAR; ++i)
  498.       kwset->next[i] = next[i];
  499.     }
  500.  
  501.   /* Fix things up for any translation table. */
  502.   if ((trans = kwset->trans) != 0)
  503.     for (i = 0; i < NCHAR; ++i)
  504.       kwset->delta[i] = delta[(unsigned char) trans[i]];
  505.   else
  506.     for (i = 0; i < NCHAR; ++i)
  507.       kwset->delta[i] = delta[i];
  508.  
  509.   return 0;
  510. }
  511.  
  512. #define U(C) ((unsigned char) (C))
  513.  
  514. /* Fast boyer-moore search. */
  515. static char *
  516. bmexec(kws, text, size)
  517.      kwset_t kws;
  518.      char *text;
  519.      size_t size;
  520. {
  521.   struct kwset *kwset;
  522.   register unsigned char *d1;
  523.   register char *ep, *sp, *tp;
  524.   register int d, gc, i, len, md2;
  525.  
  526.   kwset = (struct kwset *) kws;
  527.   len = kwset->mind;
  528.  
  529.   if (len == 0)
  530.     return text;
  531.   if (len > size)
  532.     return 0;
  533.   if (len == 1)
  534.     return memchr(text, kwset->target[0], size);
  535.  
  536.   d1 = kwset->delta;
  537.   sp = kwset->target + len;
  538.   gc = U(sp[-2]);
  539.   md2 = kwset->mind2;
  540.   tp = text + len;
  541.  
  542.   /* Significance of 12: 1 (initial offset) + 10 (skip loop) + 1 (md2). */
  543.   if (size > 12 * len)
  544.     /* 11 is not a bug, the initial offset happens only once. */
  545.     for (ep = text + size - 11 * len;;)
  546.       {
  547.     while (tp <= ep)
  548.       {
  549.         d = d1[U(tp[-1])], tp += d;
  550.         d = d1[U(tp[-1])], tp += d;
  551.         if (d == 0)
  552.           goto found;
  553.         d = d1[U(tp[-1])], tp += d;
  554.         d = d1[U(tp[-1])], tp += d;
  555.         d = d1[U(tp[-1])], tp += d;
  556.         if (d == 0)
  557.           goto found;
  558.         d = d1[U(tp[-1])], tp += d;
  559.         d = d1[U(tp[-1])], tp += d;
  560.         d = d1[U(tp[-1])], tp += d;
  561.         if (d == 0)
  562.           goto found;
  563.         d = d1[U(tp[-1])], tp += d;
  564.         d = d1[U(tp[-1])], tp += d;
  565.       }
  566.     break;
  567.       found:
  568.     if (U(tp[-2]) == gc)
  569.       {
  570.         for (i = 3; i <= len && U(tp[-i]) == U(sp[-i]); ++i)
  571.           ;
  572.         if (i > len)
  573.           return tp - len;
  574.       }
  575.     tp += md2;
  576.       }
  577.  
  578.   /* Now we have only a few characters left to search.  We
  579.      carefully avoid ever producing an out-of-bounds pointer. */
  580.   ep = text + size;
  581.   d = d1[U(tp[-1])];
  582.   while (d <= ep - tp)
  583.     {
  584.       d = d1[U((tp += d)[-1])];
  585.       if (d != 0)
  586.     continue;
  587.       if (U(tp[-2]) == gc)
  588.     {
  589.       for (i = 3; i <= len && U(tp[-i]) == U(sp[-i]); ++i)
  590.         ;
  591.       if (i > len)
  592.         return tp - len;
  593.     }
  594.       d = md2;
  595.     }
  596.  
  597.   return 0;
  598. }
  599.  
  600. /* Hairy multiple string search. */
  601. static char *
  602. cwexec(kws, text, len, kwsmatch)
  603.      kwset_t kws;
  604.      char *text;
  605.      size_t len;
  606.      struct kwsmatch *kwsmatch;
  607. {
  608.   struct kwset *kwset;
  609.   struct trie **next, *trie, *accept;
  610.   char *beg, *lim, *mch, *lmch;
  611.   register unsigned char c, *delta;
  612.   register int d;
  613.   register char *end, *qlim;
  614.   register struct tree *tree;
  615.   register char *trans;
  616.  
  617. #ifdef lint
  618.   accept = NULL;
  619. #endif
  620.  
  621.   /* Initialize register copies and look for easy ways out. */
  622.   kwset = (struct kwset *) kws;
  623.   if (len < kwset->mind)
  624.     return 0;
  625.   next = kwset->next;
  626.   delta = kwset->delta;
  627.   trans = kwset->trans;
  628.   lim = text + len;
  629.   end = text;
  630.   if ((d = kwset->mind) != 0)
  631.     mch = 0;
  632.   else
  633.     {
  634.       mch = text, accept = kwset->trie;
  635.       goto match;
  636.     }
  637.  
  638.   if (len >= 4 * kwset->mind)
  639.     qlim = lim - 4 * kwset->mind;
  640.   else
  641.     qlim = 0;
  642.  
  643.   while (lim - end >= d)
  644.     {
  645.       if (qlim && end <= qlim)
  646.     {
  647.       end += d - 1;
  648.       while ((d = delta[c = *end]) && end < qlim)
  649.         {
  650.           end += d;
  651.           end += delta[(unsigned char) *end];
  652.           end += delta[(unsigned char) *end];
  653.         }
  654.       ++end;
  655.     }
  656.       else
  657.     d = delta[c = (end += d)[-1]];
  658.       if (d)
  659.     continue;
  660.       beg = end - 1;
  661.       trie = next[c];
  662.       if (trie->accepting)
  663.     {
  664.       mch = beg;
  665.       accept = trie;
  666.     }
  667.       d = trie->shift;
  668.       while (beg > text)
  669.     {
  670.       c = trans ? trans[(unsigned char) *--beg] : *--beg;
  671.       tree = trie->links;
  672.       while (tree && c != tree->label)
  673.         if (c < tree->label)
  674.           tree = tree->llink;
  675.         else
  676.           tree = tree->rlink;
  677.       if (tree)
  678.         {
  679.           trie = tree->trie;
  680.           if (trie->accepting)
  681.         {
  682.           mch = beg;
  683.           accept = trie;
  684.         }
  685.         }
  686.       else
  687.         break;
  688.       d = trie->shift;
  689.     }
  690.       if (mch)
  691.     goto match;
  692.     }
  693.   return 0;
  694.  
  695.  match:
  696.   /* Given a known match, find the longest possible match anchored
  697.      at or before its starting point.  This is nearly a verbatim
  698.      copy of the preceding main search loops. */
  699.   if (lim - mch > kwset->maxd)
  700.     lim = mch + kwset->maxd;
  701.   lmch = 0;
  702.   d = 1;
  703.   while (lim - end >= d)
  704.     {
  705.       if ((d = delta[c = (end += d)[-1]]) != 0)
  706.     continue;
  707.       beg = end - 1;
  708.       if (!(trie = next[c]))
  709.     {
  710.       d = 1;
  711.       continue;
  712.     }
  713.       if (trie->accepting && beg <= mch)
  714.     {
  715.       lmch = beg;
  716.       accept = trie;
  717.     }
  718.       d = trie->shift;
  719.       while (beg > text)
  720.     {
  721.       c = trans ? trans[(unsigned char) *--beg] : *--beg;
  722.       tree = trie->links;
  723.       while (tree && c != tree->label)
  724.         if (c < tree->label)
  725.           tree = tree->llink;
  726.         else
  727.           tree = tree->rlink;
  728.       if (tree)
  729.         {
  730.           trie = tree->trie;
  731.           if (trie->accepting && beg <= mch)
  732.         {
  733.           lmch = beg;
  734.           accept = trie;
  735.         }
  736.         }
  737.       else
  738.         break;
  739.       d = trie->shift;
  740.     }
  741.       if (lmch)
  742.     {
  743.       mch = lmch;
  744.       goto match;
  745.     }
  746.       if (!d)
  747.     d = 1;
  748.     }
  749.  
  750.   if (kwsmatch)
  751.     {
  752.       kwsmatch->index = accept->accepting / 2;
  753.       kwsmatch->beg[0] = mch;
  754.       kwsmatch->size[0] = accept->depth;
  755.     }
  756.   return mch;
  757. }
  758.  
  759. /* Search through the given text for a match of any member of the
  760.    given keyword set.  Return a pointer to the first character of
  761.    the matching substring, or NULL if no match is found.  If FOUNDLEN
  762.    is non-NULL store in the referenced location the length of the
  763.    matching substring.  Similarly, if FOUNDIDX is non-NULL, store
  764.    in the referenced location the index number of the particular
  765.    keyword matched. */
  766. char *
  767. kwsexec(kws, text, size, kwsmatch)
  768.      kwset_t kws;
  769.      char *text;
  770.      size_t size;
  771.      struct kwsmatch *kwsmatch;
  772. {
  773.   struct kwset *kwset;
  774.   char *ret;
  775.  
  776.   kwset = (struct kwset *) kws;
  777.   if (kwset->words == 1 && kwset->trans == 0)
  778.     {
  779.       ret = bmexec(kws, text, size);
  780.       if (kwsmatch != 0 && ret != 0)
  781.     {
  782.       kwsmatch->index = 0;
  783.       kwsmatch->beg[0] = ret;
  784.       kwsmatch->size[0] = kwset->mind;
  785.     }
  786.       return ret;
  787.     }
  788.   else
  789.     return cwexec(kws, text, size, kwsmatch);
  790. }
  791.  
  792. /* Free the components of the given keyword set. */
  793. void
  794. kwsfree(kws)
  795.      kwset_t kws;
  796. {
  797.   struct kwset *kwset;
  798.  
  799.   kwset = (struct kwset *) kws;
  800.   obstack_free(&kwset->obstack, 0);
  801.   free(kws);
  802. }
  803.